/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
1、Promose 就是一个类 在执行这个类得时候，需要传递一个执行器进去，执行器会立即执行
2、Promise中有三种状态  分别为成功 fulfilled 失败  rejected  等待 pending
pedding --> fulfilled
pedding --> rejected
一旦状态确认就不会更改
3、 resolve和reject函数是用来更改状态的
    resolve : fulfilled
    reject : rejected
4、 then方法内部做的事情就是判断状态 如果状态是成功 调用成功的回调函数，如果状态是失败，调用失败的回调函数 then方法是被定义在原型对象上
7、then方法是可以被链式调用的，后面的then方法的回调拿到的是上一个then方法的回调函数的返回值

*/
const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失败

class MyPromise {
  constructor(executor) {
    try {
      executor(this.resolve, this.reject);
    } catch (err) {
      this.reject(err);
    }
  }
  status = PENDING;
  // 成功得值
  value = undefined;
  // 失败得值
  reason = undefined;
  // 成功回调
  successCallback = [];
  // 失败回调
  failCallback = [];

  resolve = (value) => {
    // 如果状态不是等待 阻止程序向下运行
    if (this.status !== PENDING) return;
    // 将状态改为成功
    this.status = FULFILLED;
    // 保存成功的值
    this.value = value;
    // 判断成功回调是否存在，存在就调用
    //  this.successCallback && this.successCallback(this.value);
    while (this.successCallback.length) this.successCallback.shift()();
  };
  reject = (reason) => {
    // 如果状态不是等待 阻止程序向下运行
    if (this.status !== PENDING) return;
    // 将状态改为失败
    this.status = REJECTED;
    // 保存失败的原因
    this.reason = reason;
    // 判断失败回调是否存在，存在调用失败回调
    // this.failCallback && this.failCallback(this.reason);
    while (this.failCallback.length) this.failCallback.shift()();
  };
  then(successCallback, failCallback) {
    successCallback = successCallback ? successCallback : value => value;
    failCallback = failCallback ? failCallback : reason => { throw reason };
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            let x = successCallback(this.value);
            // 判断x的值是否为普通值还是Promise对象
            // 如果是普通值 直接调用resolve
            // 如果是Promise对象 查看promise对象返回的结果
            // 再根据promise对象返回的结果 决定调用resolve 还是reject
            // 防止循环调用  拿不到promise2 是代码变异步操作

            resolvePromise(promise2, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        }, 0);
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = failCallback(this.reason);
            // 判断x的值是否为普通值还是Promise对象
            // 如果是普通值 直接调用resolve
            // 如果是Promise对象 查看promise对象返回的结果
            // 再根据promise对象返回的结果 决定调用resolve 还是reject
            // 防止循环调用  拿不到promise2 是代码变异步操作

            resolvePromise(promise2, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        }, 0);
      } else {
        // 异步操作
        // 将成功和失败回调函数存储起来
        // setTimeout(() => {
        //   try {
        //     let x = failCallback(this.reason);
        //     // 判断x的值是否为普通值还是Promise对象
        //     // 如果是普通值 直接调用resolve
        //     // 如果是Promise对象 查看promise对象返回的结果
        //     // 再根据promise对象返回的结果 决定调用resolve 还是reject
        //     // 防止循环调用  拿不到promise2 是代码变异步操作

        //     resolvePromise(promise2, x, resolve, reject);
        //   } catch (err) {
        //     reject(err);
        //   }
        // }, 0);
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              let x = successCallback(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (err) {
              reject(err);
            }
          }, 0);
        });
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              let x = failCallback(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (err) {
              reject(err);
            }
          }, 0);
        });
      }
    });
    return promise2;
  }
  finally (callback) {
      return this.then(value => {
          return MyPromise.resolve(callback()).then(() => value)
        }, reason => {
          return MyPromise.resolve(callback()).then(() => { throw reason })
        }
            )
  }
  catch (failCallback) {
      return this.then(undefined,failCallback)
  }
  static all(array) {
      let result = [];
      let index = 0;
      // function addData (key ,value) {
      //   result[key] = value;
      //   index++;
      //   if (index === array.length) {
      //       resolve(result)
      //   }
      // }
    return new MyPromise((resolve, reject) => {
        function addData (key ,value) {
            result[key] = value;
            index++;
            if (index === array.length) {
                resolve(result)
            }
          }
        for(let i =0; i < array.length; i++) {
            let current = array[i];
            if(current instanceof MyPromise) {
                current.then(value => addData(i, value) )
                // promise 对象
                current.then (value => addData(i , value), reason=>reject(reason))
            }else {
                // 普通值
                addData(i, array[i])
            }
        }
       
    })
  }
  static resolve (value) {
      if(value instanceof MyPromise) return value;
      return new MyPromise(resolve =>resolve(value))
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject("Chaining cycle detected for promise #<Promise>");
  }
  if (x instanceof MyPromise) {
    // x.then(value=> resolve(value),reason=> {reject(reason)})
    x.then(resolve, reject);
  } else {
    resolve(x);
  }
}
